#ifndef __SHM_HPP__
#define __SHM_HPP__

#include <iostream>
#include <sys/types.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <string>
#include <cstring>
#include <unistd.h>

using namespace std;
const int gCreater = 1;
const int gUser = 2;
const string pathname = "/home/tsx/linux/24-5-2/myShm/4.shm";
const int proj_id = 0x66;
const size_t gShmSize = 4096;

class Shm
{
private:
    key_t GetKey()
    { // 获得key
        key_t k = ftok(_pathname.c_str(), _proj_id);
        if (k < 0)
        {
            perror("ftok");
        }
        return k;
    }

    int GetShm(key_t key, int size, int flag)
    { // 通过系统调用获得shm
        int shmid = shmget(key, size, flag);
        if (shmid < 0)
        {
            perror("shmget");
        }
        return shmid;
    }

    string PrintWho()
    {
        if (_who == 1)
            return "gCrearter";
        else if (_who == 2)
            return "gUser";
        else
            return "None";
    }

    void *AttachShm()
    {
        if (_shmaddr != nullptr)
        {
            DetachShm();
        }
        void *shmaddr = shmat(_shmid, nullptr, 0);
        if (shmaddr == nullptr)
        {
            perror("shmat");
        }
        cout << "who: " << PrintWho() << " attachshm :" << endl;
        return shmaddr;
    }

    void DetachShm()
    {
        if (_shmaddr == nullptr)
        {
            return;
        }
        shmdt(_shmaddr);
        cout << "who: " << PrintWho() << " deattachshm :" << endl;
    }

    void DeleteShm()
    {
        if (_who == gCreater)
        {
            int res = shmctl(_shmid, IPC_RMID, nullptr);
            if (res == -1)
            {
                perror("shmclt");
            }
        }
    }

public:
    Shm(const string &pathname, const int proj_id, int who)
        : _pathname(pathname), _proj_id(proj_id), _who(who), _shmaddr(nullptr)
    {
        // 获得_key
        _key = GetKey();
        // 创建shm
        if (_who == gCreater)
        {
            GetShmForCreater();
        }
        else if (_who == gUser)
        {
            GetShmForUse();
        }
        _shmaddr = AttachShm(); // 连接
    }
    ~Shm()
    {
        DetachShm(); // 分离连接shm
        DeleteShm(); // 删除shm
    }

    bool GetShmForCreater()
    { // server创建shm
        _shmid = GetShm(_key, gShmSize, IPC_CREAT | IPC_EXCL | 0666);
        if (_shmid < 0)
            return false;
        cout << "server成功创建shm" << endl;
        return true;
    }

    void InitShmaddr()
    {
        if (_shmaddr)
        {
            memset(_shmaddr, 0, sizeof gShmSize);
        }
    }
    void *GetShmaddr()
    {
        return _shmaddr;
    }
    bool GetShmForUse()
    {
        _shmid = GetShm(_key, gShmSize, IPC_CREAT | 0666);
        if (_shmid < 0)
            return false;
        cout << "client成功获得shm" << endl;
        return true;
    }

private:
    key_t _key;
    int _shmid;
    int _id;
    string _pathname;
    int _who;
    int _proj_id;
    void *_shmaddr;
};

#endif